const moment = require('moment');

const filterValue = (v, t) => {
    switch(t) {
        case 'String':
            return `${v}` || undefined;
        case 'Number':
            return Number(v) || undefined;
        case 'Date':
            return v ? new Date(Number(v)) || undefined : undefined;
        case 'DateString':
            return (v && new Date(Number(v))) ? moment(new Date(Number(v))).format('YYYY-MM-DD') : undefined;
        default:
            return v || undefined;
    }
}

const makeQueryFilters = (req, d, res) => {
    // sort options
    if(req.query.sort && res) {
        res.locals.options =res.locals.options || {};

        let direction = 1;
        let sortField = req.query.sort || '';
        if (sortField.startsWith('-')) {
            direction = -1;
            sortField = sortField.substr(1);
        }

        if(sortField && direction) {
            if(sortField === 'LastUpdateDate') {
                res.locals.options.sort = { 推荐指数: 'desc', 时间: 'desc', LastUpdateDate: 'desc' }
            } else {
                res.locals.options.sort = {};
                res.locals.options.sort[sortField] = direction; 
            }
        }
    }

    const def = queryDefs[d];
    if (!def || !req.query) return {};

    const ret = {};

    const fields = Object.keys(def);
    fields.forEach((fld) => {
        const fDef = def[fld];
        let fType = 'String'; // could be Number, String, Date
        let range;
        let filter;

        if(typeof fDef === 'string') {
            fType = fDef;
        } else if (fDef.type) {
            fType = fDef.type;
            range = !!fDef.range;
        } else if (typeof fDef === 'object') {
            filter = fDef;
        } else if (typeof fDef === 'function') {
            filter = fDef(req, res);
        }

        if (!filter) {
            const fValues = (req.query[fld] || '').split(',');

            if (range) {
                const fPair = fValues[0].split('~');

                if (fPair.length === 2) {
                    const min = filterValue(fPair[0], fType);
                    const max = filterValue(fPair[1], fType)

                    if (min !== void 0) {
                        filter = filter || {};
                        filter.$gte = min;
                    }

                    if (max !== void 0) {
                        filter = filter || {};
                        filter.$lt = max;
                    }
                }
            } else {
                const fList = fValues.map((fv) => {
                    return filterValue(fv);
                }).filter((fv) => fv !== void 0) || [];

                if (fList.length) {
                    filter = {
                        $in: fList,
                    };
                }
            }
        }

        if(filter) {
            ret[fld] = filter;
        }
    });

    return ret;
}


// get dict label according to the locale
const dictCache = {};
function _dictLabel (res, dict, val, isList = false, moreFields = []) {
    if (!dict || !dict || !val) return undefined;

    const getFinalFields = (moreFields.length > 0) ? ((d) => {
        const ret = {};
        const allFields = [...moreFields, 'Label'];
        for(let i = 0; i < allFields.length; i += 1) {
            const fld = allFields[i];

            if (!ret[fld]) {
                ret[fld] = d[fld];
            }
        }

        return ret;
    }) : ((d) => d.Label);

    if (isList && Array.isArray(val)) {
        const filteredList = dict.filter(d => val.indexOf(d.Value) >= 0).map(getFinalFields);
        if (moreFields.length <= 0) {
            return filteredList.join(',');
        }

        return filteredList;
    }

    const theDict = dict.find(d => d.Value === val);

    if (theDict) return getFinalFields(theDict);

    return undefined;
}

/**
 * 
 * @param {Object} req The req object from the request
 * @param {Object} res The res object from the request
 * @param {String} field The field name in the result data
 * @param {String} name The dict name 
 * @param {Boolean} isList Whether the value of the field is array
 * @returns 
 */
const getDictLabel = async (req, res, field, name, isList = false, moreFields = []) => {
    if (!res || !res.locals.data || !field || !name || !res.app.modules['dictionary']) return;
    const locale = req.query.locale || req.body.locale;

    const dict = (dictCache[locale] && dictCache[locale][name]) || await res.app.modules['dictionary'].dict(name, false, locale);
    if (!dictCache[locale] || !dictCache[locale][name]) {
        dictCache[locale] = dictCache[locale] || {};
        dictCache[locale][name] = dict;
    }

    if (!dict) {
        res.app.logger.error(`Failed to get dict ${name}`);
        return;
    }

    if (res.locals.data.docs) {
        for (let i = 0; i < res.locals.data.docs.length; i += 1) {
            const doc = res.locals.data.docs[i];

            if (!doc[field]) continue;

            doc[field] = _dictLabel(res, dict, doc[field], isList, moreFields);
        }
    } else {
        if (!res.locals.data[field]) return;
        res.locals.data[field] = _dictLabel(res, dict, res.locals.data[field], isList, moreFields);
    }
}

const repalceHtmlToText = (str = '', len = 100, tlen = 500, leaveSpaces = false, multiLines = false) => {
    let ret = '';

    // remove images
    ret = str.replace(/<img\/?.+?>/g,"");
    ret = ret.replace(/<video .*>(\n|.)*<\/video>/g,"");

    ret = ret.substring(0, tlen);
    ret = ret.replace(/<\/?.+?>/g,"");
    ret = ret.replace(/&[a-z]*;/g,"");

    if (multiLines) {
        // replace \n with specific string
        ret = ret.replace(/\n/g,"+++NL+++");
    } else {
        ret = ret.replace(/\n/g,"");
    }

    if (!leaveSpaces) {
        ret = ret.replace(/\s*/g,"");
    }

    if (multiLines) {
        // replace \n with specific string
        ret = ret.replace(/\+\+\+NL\+\+\+/g, '\n');
    }

    return ret.substring(0, len);
}

module.exports = {
    makeQueryFilters,
    getDictLabel,
    dictLabel: _dictLabel,
    repalceHtmlToText,
}